from pathlib import Path
from contextlib import asynccontextmanager
import shutil
from typing import Annotated


from fastapi import applications, BackgroundTasks, FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.openapi.docs import get_swagger_ui_html
from pydantic import BaseModel
from fastapi import BackgroundTasks, File, HTTPException, Request, UploadFile
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles

from app.database import Base
from app.db_connection import get_engine


def swagger_monkey_patch(*args, **kwargs):
    """
    Wrap the function which is generating the HTML for the /docs endpoint and
    overwrite the default values for the swagger js and css.
    """
    return get_swagger_ui_html(
        *args,
        **kwargs,
        swagger_js_url="static/swagger-ui-bundle.js",
        swagger_css_url="static/swagger-ui.css",
    )


# Actual monkey patch
applications.get_swagger_ui_html = swagger_monkey_patch


@asynccontextmanager
async def lifespan(app: FastAPI):
    # engine = get_engine()
    # async with engine.begin() as conn:
    #     await conn.run_sync(Base.metadata.create_all)
    #     yield
    yield
    # await engine.dispose()


# app = FastAPI(title="FastAPI接口")
app = FastAPI(lifespan=lifespan, title="FastAPI接口")


app.mount("/static", StaticFiles(directory="./static"), name="static")

# origins = [
#     "http://localhost.xxx.com",
#     "https://localhost.xxx.com",
#     "http://localhost",
#     "http://localhost:8080",
# ]

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.get("/api/")
async def root():
    """
    测试
    """
    return {"message": "Hello World"}


@app.get("/api/items/{item_id}")
async def read_item(item_id):
    """
    GET
    """
    return {"item_id": item_id}


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.post("/api/items/")
async def create_item(item: Item):
    """
    POST
    """
    return item


def write_notification(email: str, message=""):
    with open("log.txt", mode="w") as email_file:
        content = f"notification for {email}: {message}"
        email_file.write(content)


@app.post("/api/send-notification/{email}")
async def send_notification(email: str, background_tasks: BackgroundTasks):
    """
    异步任务
    """
    background_tasks.add_task(write_notification, email, message="some notification")
    return {"message": "Notification sent in the background"}


@app.post("/api/uploadfile")
async def upload_file(file: UploadFile = File(...)):
    """
    上传文件
    """
    with open(f"uploads/{file.filename}", "wb") as buffer:
        shutil.copyfileobj(file.file, buffer)
    return {"filename": file.filename}


@app.get("/api/downloadfile/{filename}", response_class=FileResponse)
async def download_file(filename: str):
    """
    下载文件
    """
    if not Path(f"uploads/{filename}").exists():
        raise HTTPException(status_code=404, detail=f"file {filename} not found")
    return FileResponse(path=f"uploads/{filename}", filename=filename)


################################################
# 下面是一个简单的示例
################################################

from typing import Annotated

from fastapi import Depends, FastAPI, HTTPException
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession

from app.db_connection import get_db_session, get_engine
from app.operations import create_ticket, delete_ticket, get_ticket, update_ticket_price


@app.get("/ticket/{ticket_id}")
async def read_ticket(
    db_session: Annotated[AsyncSession, Depends(get_db_session)],
    ticket_id: int,
):
    """
    查询对象
    """
    ticket = await get_ticket(db_session, ticket_id)
    if ticket is None:
        raise HTTPException(status_code=404, detail="Ticket not found")
    return ticket


class TicketRequest(BaseModel):
    price: float | None
    show: str | None
    user: str | None = None


@app.post("/ticket", response_model=dict[str, int])
async def create_ticket_route(
    db_session: Annotated[AsyncSession, Depends(get_db_session)],
    ticket: TicketRequest,
):
    """
    新增对象
    """
    ticket_id = await create_ticket(
        db_session,
        ticket.show,
        ticket.user,
        ticket.price,
    )
    return {"ticket_id": ticket_id}


@app.delete("/ticket/{ticket_id}")
async def delete_ticket_route(
    db_session: Annotated[AsyncSession, Depends(get_db_session)],
    ticket_id: int,
):
    """
    删除对象
    """
    ticket = await delete_ticket(db_session, ticket_id)
    if not ticket:
        raise HTTPException(status_code=404, detail="Ticket not found")
    return {"detail": "Ticket removed"}


@app.put("/ticket/{ticket_id}/price/{new_price}")
async def update_ticket_price_route(
    db_session: Annotated[AsyncSession, Depends(get_db_session)],
    ticket_id: int,
    new_price: float,
):
    """
    修改对象
    """
    updated = await update_ticket_price(db_session, ticket_id, new_price)
    if not updated:
        raise HTTPException(status_code=404, detail="Ticket not found")
    return {"detail": "Price updated"}
